#[macro_use]
extern crate serde;

use std::io::Write;
use std::panic;
use std::process::exit;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::app::run_app;
use crate::service::Plugin;
use crate::utils::{AppConfig, DATA_DIR_NAME};
use anyhow::Result;
use chrono::Local;
use console::Style;
use log::{error, LevelFilter};
use once_cell::sync::OnceCell;

mod app;
mod ssh;
mod utils;
mod service;
#[cfg(test)]
mod test;

static AES_KEY_ARR: OnceCell<Vec<u8>> = OnceCell::new();
static AES_IV_ARR: OnceCell<Vec<u8>> = OnceCell::new();
static WORK_DIR: OnceCell<String> = OnceCell::new();
static APP_DIR: OnceCell<String> = OnceCell::new();
static APP_CONFIG: OnceCell<AppConfig> = OnceCell::new();
static RUNING: OnceCell<Arc<AtomicBool>> = OnceCell::new();

pub fn success<S: AsRef<str>>(msg: S)
where
    S: std::fmt::Display,
{
    let cyan = Style::new().green().cyan();
    println!("{}", cyan.apply_to(msg))
}

pub fn log<S: AsRef<str>>(msg: S)
where
    S: std::fmt::Display,
{
    let cyan = Style::new().blue().cyan();
    println!("{}", cyan.apply_to(msg))
}

pub fn error<S: AsRef<str>>(msg: S)
where
    S: std::fmt::Display,
{
    let cyan = Style::new().red().cyan();
    println!("{}", cyan.apply_to(msg))
}

#[tokio::main(flavor = "multi_thread", worker_threads = 5)]
async fn main() -> Result<()> {
    #[cfg(not(debug_assertions))]
    panic::set_hook(Box::new(|panic_info| {
        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
            error(format!("程序错误: {}", s.to_string()));
        } else {
            error("程序错误！");
        }
    }));
    let app_dir = dirs::home_dir().unwrap_or_else(|| panic!("获取用户目录失败！")).join(DATA_DIR_NAME);
    APP_DIR.set(app_dir.to_string_lossy().to_string()).unwrap_or_else(|_| panic!("设置应用数据目录错误！"));
    APP_CONFIG.set(AppConfig::init()?).unwrap_or_else(|_| panic!("配置文件读取错误！"));
    let running = Arc::new(AtomicBool::new(true));
    let r = Arc::clone(&running);
    let _ = RUNING.set(running.clone());
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        let term = console::Term::stdout();
        let _ = term.show_cursor();
        exit(0);
    })?;
    env_logger::builder()
        .format(|buf, record| {
            writeln!(
                buf,
                "{} - {} - {}",
                Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                record.args()
            )
        })
        .filter(None, LevelFilter::Info)
        .init();

    Plugin::check_dir()?;
    match run_app().await {
        Ok(()) => {}
        Err(err) => error(err.to_string())
    };
    Ok(())
}

// #[test]
// fn test_data() -> Result<()> {
//     APP_CONFIG.set(AppConfig::init().unwrap_or_else(|_| panic!("配置初始化失败！"))).unwrap_or_else(|_| panic!("配置文件读取错误！"));
//     let aes_key: Vec<u8> = serde_json::from_str(AES_KEY)?;
//     let aes_iv: Vec<u8> = serde_json::from_str(AES_IV)?;
//     AES_KEY_ARR.set(aes_key).unwrap();
//     AES_IV_ARR.set(aes_iv).unwrap();
//     if let Ok(mut fs) = OpenOptions::new().read(true).open("/Users/rookie/Desktop/server.json") {
//         let mut content = String::new();
//         fs.read_to_string(&mut content)?;
//
//         let mut app = AppData::read_data()?;
//         app.servers.clear();
//
//         let data: Value = serde_json::from_str(&content)?;
//         let arr = data.as_array().unwrap();
//         for item in arr {
//             let server = ServerItem {
//                 label: item.get("name").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 desc: item.get("label").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 ip: item.get("host").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 port: item.get("port").unwrap().as_i64().unwrap() as i32,
//                 user_name: item.get("user").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 auth_type: item.get("auth_type").unwrap().as_i64().unwrap() as i32,
//                 password: item.get("password").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 secret_key: item.get("private_key").unwrap_or(&Value::from("")).as_str().unwrap_or("").to_string(),
//                 deploy_path: "".to_string(),
//             };
//             app.servers.push(server);
//         }
//
//         app.write_data()?;
//         print!("{:?}", app.servers);
//     }
//     Ok(())
// }
